Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Displaying Raw • Download


meshchatx/src/frontend/js/LinkUtils.js b8b40bcf163627e2f64cfea5887d95f93891e985 (b8b40bcf) Text, 5.21 KB

Tff7b72import Te6edf3GlobalState Tff7b72from Ta5d6ff"./GlobalState.js"Tb4b4b4;
Tff7b72import Te6edf3Utils Tff7b72from Ta5d6ff"./Utils.js"Tb4b4b4;

Tff7b72function Te6edf3defaultNomadPagePathTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3p Tff7b72= Te6edf3GlobalStateTb4b4b4.Te6edf3configTff7b72?Tb4b4b4.Te6edf3nomad_default_page_pathTb4b4b4;
Tff7b72return Tff7b72typeof Te6edf3p Tff7b72=== Ta5d6ff"string" Tff7b72&& Te6edf3pTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff"/page/"Tb4b4b4) Tff7b72? Te6edf3p Tff7b72: Ta5d6ff"/page/index.mu"Tb4b4b4;
Tb4b4b4}

Tff7b72function Te6edf3httpUrlHrefOrNullTb4b4b4(Te6edf3coreTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3tries Tff7b72= Tb4b4b4[Te6edf3coreTb4b4b4]Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3coreTb4b4b4.Te6edf3includesTb4b4b4(Ta5d6ff"&"Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3triesTb4b4b4.Te6edf3pushTb4b4b4(Te6edf3coreTb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff/&/gTb4b4b4, Ta5d6ff"&"Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72for Tb4b4b4(Tff7b72const Te6edf3candidate Tff7b72of Te6edf3triesTb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3u Tff7b72= Tff7b72new Te6edf3URLTb4b4b4(Te6edf3candidateTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3uTb4b4b4.Te6edf3protocol Tff7b72=== Ta5d6ff"http:" Tff7b72|| Te6edf3uTb4b4b4.Te6edf3protocol Tff7b72=== Ta5d6ff"https:"Tb4b4b4) Tb4b4b4{
Tff7b72return Te6edf3uTb4b4b4.Te6edf3hrefTb4b4b4;
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4{
T8b949e/* try next */
Tb4b4b4}
Tb4b4b4}
Tff7b72return Tff7b72nullTb4b4b4;
Tb4b4b4}

Tff7b72export Tff7b72default Tff7b72class Te6edf3LinkUtils Tb4b4b4{
T8b949e/**
* Returns canonical http(s) href or null if the string is not a safe remote URL.
*/
Tff7b72static Te6edf3httpUrlHrefOrNullTb4b4b4(Te6edf3coreTb4b4b4) Tb4b4b4{
Tff7b72return Te6edf3httpUrlHrefOrNullTb4b4b4(Te6edf3coreTb4b4b4)Tb4b4b4;
Tb4b4b4}

Tff7b72static Te6edf3protectAnchorsTb4b4b4(Te6edf3textTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3anchors Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72const Te6edf3protectedText Tff7b72= Te6edf3textTb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff/<a\b[^>]*>[\s\S]*?<\/a>/giTb4b4b4, Tb4b4b4(Te6edf3anchorTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72const Te6edf3token Tff7b72= Ta5d6ff`Ta5d6ff[[ANCHOR_Tffd700${Te6edf3anchorsTb4b4b4.Te6edf3lengthTffd700}Ta5d6ff]]Ta5d6ff`Tb4b4b4;
Te6edf3anchorsTb4b4b4.Te6edf3pushTb4b4b4(Te6edf3anchorTb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3tokenTb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72return Tb4b4b4{ Te6edf3protectedTextTb4b4b4, Te6edf3anchors Tb4b4b4}Tb4b4b4;
Tb4b4b4}

Tff7b72static Te6edf3restoreAnchorsTb4b4b4(Te6edf3textTb4b4b4, Te6edf3anchorsTb4b4b4) Tb4b4b4{
Tff7b72return Te6edf3textTb4b4b4.Te6edf3replaceTb4b4b4(Ta5d6ff/\[\[ANCHOR_(\d+)\]\]/gTb4b4b4, Tb4b4b4(Te6edf3matchTb4b4b4, Te6edf3idxTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72const Te6edf3i Tff7b72= Tffa657NumberTb4b4b4(Te6edf3idxTb4b4b4)Tb4b4b4;
Tff7b72return Tffa657NumberTb4b4b4.Te6edf3isIntegerTb4b4b4(Te6edf3iTb4b4b4) Tff7b72&& Te6edf3i Tff7b72>= T79c0ff0 Tff7b72&& Te6edf3i Tff7b72< Te6edf3anchorsTb4b4b4.Te6edf3length Tff7b72? Te6edf3anchorsTb4b4b4[Te6edf3iTb4b4b4] Tff7b72: Te6edf3matchTb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}

Tff7b72static Te6edf3splitTrailingPunctuationTb4b4b4(Te6edf3urlTb4b4b4) Tb4b4b4{
Tff7b72let Te6edf3core Tff7b72= Te6edf3urlTb4b4b4;
Tff7b72let Te6edf3suffix Tff7b72= Ta5d6ff""Tb4b4b4;
Tff7b72const Te6edf3alwaysTrim Tff7b72= Tff7b72new Tffa657SetTb4b4b4(Tb4b4b4[Ta5d6ff"."Tb4b4b4, Ta5d6ff","Tb4b4b4, Ta5d6ff"!"Tb4b4b4, Ta5d6ff"?"Tb4b4b4, Ta5d6ff":"Tb4b4b4, Ta5d6ff";"Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72while Tb4b4b4(Te6edf3coreTb4b4b4.Te6edf3length Tff7b72> T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3ch Tff7b72= Te6edf3coreTb4b4b4.Te6edf3atTb4b4b4(Tff7b72-T79c0ff1Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3alwaysTrimTb4b4b4.Te6edf3hasTb4b4b4(Te6edf3chTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3suffix Tff7b72= Te6edf3ch Tff7b72+ Te6edf3suffixTb4b4b4;
Te6edf3core Tff7b72= Te6edf3coreTb4b4b4.Te6edf3sliceTb4b4b4(T79c0ff0Tb4b4b4, Tff7b72-T79c0ff1Tb4b4b4)Tb4b4b4;
Tff7b72continueTb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3ch Tff7b72=== Ta5d6ff")" Tff7b72|| Te6edf3ch Tff7b72=== Ta5d6ff"]"Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3open Tff7b72= Te6edf3ch Tff7b72=== Ta5d6ff")" Tff7b72? Ta5d6ff"(" Tff7b72: Ta5d6ff"["Tb4b4b4;
Tff7b72const Te6edf3close Tff7b72= Te6edf3chTb4b4b4;
Tff7b72const Te6edf3opens Tff7b72= Tb4b4b4[Tb4b4b4...Te6edf3coreTb4b4b4]Tb4b4b4.Te6edf3filterTb4b4b4(Tb4b4b4(Te6edf3cTb4b4b4) Tb4b4b4=> Te6edf3c Tff7b72=== Te6edf3openTb4b4b4)Tb4b4b4.Te6edf3lengthTb4b4b4;
Tff7b72const Te6edf3closes Tff7b72= Tb4b4b4[Tb4b4b4...Te6edf3coreTb4b4b4]Tb4b4b4.Te6edf3filterTb4b4b4(Tb4b4b4(Te6edf3cTb4b4b4) Tb4b4b4=> Te6edf3c Tff7b72=== Te6edf3closeTb4b4b4)Tb4b4b4.Te6edf3lengthTb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3closes Tff7b72> Te6edf3opensTb4b4b4) Tb4b4b4{
Te6edf3suffix Tff7b72= Te6edf3ch Tff7b72+ Te6edf3suffixTb4b4b4;
Te6edf3core Tff7b72= Te6edf3coreTb4b4b4.Te6edf3sliceTb4b4b4(T79c0ff0Tb4b4b4, Tff7b72-T79c0ff1Tb4b4b4)Tb4b4b4;
Tff7b72continueTb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tff7b72breakTb4b4b4;
Tb4b4b4}
Tff7b72return Tb4b4b4{ Te6edf3coreTb4b4b4, Te6edf3suffix Tb4b4b4}Tb4b4b4;
Tb4b4b4}

T8b949e/**
* Detects and wraps Reticulum (NomadNet and LXMF) links in HTML.
* Supports nomadnet://<hash>, nomadnet@<hash>, lxmf://<hash>, lxmf@<hash>, lxmf:<hash>,
* and bare <hash>:/path (NomadNet path form only — no bare hash without prefix).
*/
Tff7b72static Te6edf3renderReticulumLinksTb4b4b4(Te6edf3textTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3textTb4b4b4) Tff7b72return Ta5d6ff""Tb4b4b4;

T8b949e// Hash is 32 hex chars. Path is optional (NomadNet only).
Tff7b72const Te6edf3hashPattern Tff7b72= Ta5d6ff"[a-fA-F0-9]{32}"Tb4b4b4;
T8b949e// Optional prefix, then hash, optional path. Bare hashes with no prefix and no
T8b949e// path are intentionally skipped to avoid false positives inside URLs.
Tff7b72const Te6edf3reticulumRegex Tff7b72= Tff7b72new Tffa657RegExpTb4b4b4(
Ta5d6ff`Ta5d6ff(nomadnet://|nomadnet@|lxmf://|lxmf@|lxmf:)?(Tffd700${Te6edf3hashPatternTffd700}Ta5d6ff)(?::(/[Ta5d6ff\\Ta5d6ffwTa5d6ff\\Ta5d6ffd./?%&=_-]*))?Ta5d6ff`Tb4b4b4,
Ta5d6ff"g"
Tb4b4b4)Tb4b4b4;

Tff7b72return Te6edf3textTb4b4b4.Te6edf3replaceTb4b4b4(Te6edf3reticulumRegexTb4b4b4, Tb4b4b4(Te6edf3matchTb4b4b4, Te6edf3prefixTb4b4b4, Te6edf3hashTb4b4b4, Te6edf3pathTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3prefix Tff7b72&& Tff7b72!Te6edf3pathTb4b4b4) Tb4b4b4{
Tff7b72return Te6edf3matchTb4b4b4;
Tb4b4b4}

Tff7b72const Te6edf3isNomadNet Tff7b72=
Tb4b4b4(Te6edf3prefix Tff7b72&& Tb4b4b4(Te6edf3prefixTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff"nomadnet://"Tb4b4b4) Tff7b72|| Te6edf3prefixTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff"nomadnet@"Tb4b4b4)Tb4b4b4)Tb4b4b4) Tff7b72|| Tff7b72!Tff7b72!Te6edf3pathTb4b4b4;

Tff7b72if Tb4b4b4(Te6edf3isNomadNetTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3fullPath Tff7b72= Te6edf3path Tff7b72|| Te6edf3defaultNomadPagePathTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3url Tff7b72= Ta5d6ff`Tffd700${Te6edf3hashTffd700}Ta5d6ff:Tffd700${Te6edf3fullPathTffd700}Ta5d6ff`Tb4b4b4;
Tff7b72const Te6edf3safeAttr Tff7b72= Te6edf3UtilsTb4b4b4.Te6edf3escapeHtmlTb4b4b4(Te6edf3urlTb4b4b4)Tb4b4b4;
Tff7b72return Ta5d6ff`Ta5d6ff<a href="#" class="nomadnet-link text-blue-600 dark:text-blue-400 hover:underline font-mono" data-nomadnet-url="Tffd700${Te6edf3safeAttrTffd700}Ta5d6ff">Tffd700${Te6edf3matchTffd700}Ta5d6ff</a>Ta5d6ff`Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72return Ta5d6ff`Ta5d6ff<a href="#" class="lxmf-link text-blue-600 dark:text-blue-400 hover:underline font-mono" data-lxmf-address="Tffd700${Te6edf3hashTffd700}Ta5d6ff">Tffd700${Te6edf3matchTffd700}Ta5d6ff</a>Ta5d6ff`Tb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}

T8b949e/**
* Basic URL detection for standard http/https links.
*/
Tff7b72static Te6edf3renderStandardLinksTb4b4b4(Te6edf3textTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3textTb4b4b4) Tff7b72return Ta5d6ff""Tb4b4b4;

Tff7b72const Te6edf3urlRegex Tff7b72= Ta5d6ff/(^|[^\w"'=])(https?:\/\/[^\s<'"]+)/gTb4b4b4;
Tff7b72return Te6edf3textTb4b4b4.Te6edf3replaceTb4b4b4(Te6edf3urlRegexTb4b4b4, Tb4b4b4(Te6edf3matchTb4b4b4, Te6edf3prefixTb4b4b4, Te6edf3urlTb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72const Tb4b4b4{ Te6edf3coreTb4b4b4, Te6edf3suffix Tb4b4b4} Tff7b72= Tff7b72thisTb4b4b4.Te6edf3splitTrailingPunctuationTb4b4b4(Te6edf3urlTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3coreTb4b4b4) Tb4b4b4{
Tff7b72return Te6edf3matchTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3href Tff7b72= Te6edf3httpUrlHrefOrNullTb4b4b4(Te6edf3coreTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3hrefTb4b4b4) Tb4b4b4{
Tff7b72return Te6edf3matchTb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3label Tff7b72= Te6edf3UtilsTb4b4b4.Te6edf3escapeHtmlTb4b4b4(Te6edf3coreTb4b4b4)Tb4b4b4;
Tff7b72return Ta5d6ff`Tffd700${Te6edf3prefixTffd700}Ta5d6ff<a href="Tffd700${Te6edf3hrefTffd700}Ta5d6ff" target="_blank" rel="noopener noreferrer" class="text-blue-600 dark:text-blue-400 hover:underline">Tffd700${Te6edf3labelTffd700}Ta5d6ff</a>Tffd700${Te6edf3suffixTffd700}Ta5d6ff`Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}

T8b949e/**
* Applies all link rendering.
*/
Tff7b72static Te6edf3renderAllLinksTb4b4b4(Te6edf3textTb4b4b4) Tb4b4b4{
Tff7b72const Tb4b4b4{ Te6edf3protectedTextTb4b4b4, Te6edf3anchors Tb4b4b4} Tff7b72= Tff7b72thisTb4b4b4.Te6edf3protectAnchorsTb4b4b4(Te6edf3textTb4b4b4)Tb4b4b4;
Tff7b72let Te6edf3rendered Tff7b72= Tff7b72thisTb4b4b4.Te6edf3renderStandardLinksTb4b4b4(Te6edf3protectedTextTb4b4b4)Tb4b4b4;
Te6edf3rendered Tff7b72= Tff7b72thisTb4b4b4.Te6edf3renderReticulumLinksTb4b4b4(Te6edf3renderedTb4b4b4)Tb4b4b4;
Tff7b72return Tff7b72thisTb4b4b4.Te6edf3restoreAnchorsTb4b4b4(Te6edf3renderedTb4b4b4, Te6edf3anchorsTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────